package edu.upf.opencities.dao.connection;

import java.io.FileInputStream;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import org.apache.cassandra.auth.SimpleAuthenticator;
import org.apache.log4j.Logger;

import me.prettyprint.cassandra.model.CqlQuery;
import me.prettyprint.cassandra.model.CqlRows;
import me.prettyprint.cassandra.serializers.StringSerializer;
import me.prettyprint.cassandra.service.FailoverPolicy;
import me.prettyprint.cassandra.service.OperationType;
import me.prettyprint.cassandra.utils.TimeUUIDUtils;
import me.prettyprint.hector.api.ClockResolution;
import me.prettyprint.hector.api.Cluster;
import me.prettyprint.hector.api.ConsistencyLevelPolicy;
import me.prettyprint.hector.api.HConsistencyLevel;
import me.prettyprint.hector.api.Keyspace;
import me.prettyprint.hector.api.beans.HColumn;
import me.prettyprint.hector.api.beans.HSuperColumn;
import me.prettyprint.hector.api.beans.OrderedRows;
import me.prettyprint.hector.api.beans.OrderedSuperRows;
import me.prettyprint.hector.api.beans.Row;
import me.prettyprint.hector.api.beans.Rows;
import me.prettyprint.hector.api.beans.SuperRow;
import me.prettyprint.hector.api.beans.SuperRows;
import me.prettyprint.hector.api.factory.HFactory;
import me.prettyprint.hector.api.mutation.MutationResult;
import me.prettyprint.hector.api.mutation.Mutator;
import me.prettyprint.hector.api.query.ColumnQuery;
import me.prettyprint.hector.api.query.MultigetSliceQuery;
import me.prettyprint.hector.api.query.MultigetSubSliceQuery;
import me.prettyprint.hector.api.query.MultigetSuperSliceQuery;
import me.prettyprint.hector.api.query.QueryResult;
import me.prettyprint.hector.api.query.RangeSlicesQuery;
import me.prettyprint.hector.api.query.RangeSuperSlicesQuery;
import me.prettyprint.hector.api.query.SubSliceQuery;
import me.prettyprint.hector.api.query.SuperColumnQuery;

import edu.upf.opencities.datamodel.GlobalVar;
import edu.upf.opencities.datamodel.OSNEntry;
import edu.upf.opencities.datamodel.OSNService;
import edu.upf.opencities.datamodel.User;

public class CassandraServiceConnectorImpl implements CassandraServiceConnector {

	public static Logger logger = Logger.getLogger(CassandraServiceConnectorImpl.class);
	
	private static final StringSerializer se = new StringSerializer();
	private Cluster cluster = null;
	private Keyspace ks = null; 
	
	
    private Properties props;
	private String cassandraHOST;
	private String cassandraPORT;
	private String cassandraCluster;
	private String cassandraKeySpace;
    private String cassandraUserName;
	private String cassandraPassword;
	
	public CassandraServiceConnectorImpl(){
		//Properties management
        props = new Properties();

        try {
        	//props.load(new FileInputStream("cassandra-conf.properties") );
        	//props.load(this.getClass().
            //	getResourceAsStream("/edu/upf/opencities/dao/connection/cassandra-conf.properties"));
        	props.load(this.getClass().
            	getResourceAsStream("/cassandra-conf.properties"));
            this.cassandraHOST = props.getProperty("cassandraHOST");
            this.cassandraPORT = props.getProperty("cassandraPORT");
            this.cassandraCluster = props.getProperty("cassandraCluster");
            this.cassandraKeySpace = props.getProperty("cassandraKeySpace");
        	this.cassandraUserName = props.getProperty("cassandraUserName");
            this.cassandraPassword = props.getProperty("cassandraPassword");
    		
        } catch (IOException e) {
            e.printStackTrace();
        }
	}
	
	@Override
	public void connect() {
		// Create a cluster
		this.cluster = HFactory.getOrCreateCluster(cassandraCluster, cassandraHOST+":"+cassandraPORT);
		// Choose a keyspace with authentication
		Map<String, String> credentials = new HashMap<String, String>();
		credentials.put(SimpleAuthenticator.USERNAME_KEY, cassandraUserName);
		credentials.put(SimpleAuthenticator.PASSWORD_KEY, cassandraPassword);
		final ConsistencyLevelPolicy policy = new ConsistencyLevelPolicy() {
			@Override
			public HConsistencyLevel get(OperationType op) {
				// TODO Auto-generated method stub
				return HConsistencyLevel.ONE;
			}
			@Override
			public HConsistencyLevel get(OperationType op, String cfName) {
				// TODO Auto-generated method stub
				return HConsistencyLevel.ONE;
			}
		};

		this.ks = HFactory.createKeyspace(cassandraKeySpace, cluster, policy, FailoverPolicy.FAIL_FAST, credentials);
		logger.info("Connected to Cluster: "+cassandraCluster+ "in KeySpace: " + cassandraKeySpace);

	}

	@Override
	public void disconnect() {
	    ks = null;
	    cluster = null;
	    logger.info("Disconnected from Cluster: "+cassandraCluster+ " in KeySpace: " + cassandraKeySpace);
	}

	@Override
	public String registerService( String mail,
			String serviceName, String servicePassword, String owner,
			String description, String updatePeriod, String section,
			String latitude, String longitude, List<String> tagList ) {
		
		// Set ColumnFamily name
		String cf = "Services";
		//Set row name
		String rowKey = mail;
		//Set super column name using UUID
		long clock = HFactory.createClock();
		//UUID uuid = TimeUUIDUtils.getTimeUUID(clock);
		//String scKey = uuid.toString(); 
		String scKey = String.valueOf(clock);
		
		logger.info("***** Starting registering service <"+scKey+"> *****");
		
		// We create a List of columns using columns 
		@SuppressWarnings("unchecked")
		List<HColumn<String, String>> columns = Arrays.asList(
		    		HFactory.createColumn(GlobalVar.SERVICE_ID, scKey, se, se),
		    		HFactory.createColumn(GlobalVar.MAIL, mail, se, se),
		    		HFactory.createColumn(GlobalVar.SERVICE_NAME, serviceName, se, se),
		    		HFactory.createColumn(GlobalVar.SERVICE_PASSWORD, servicePassword, se, se),
		    		HFactory.createColumn(GlobalVar.SERVICE_OWNER, owner, se, se),
		    		HFactory.createColumn(GlobalVar.SERVICE_DESCRIPTION, description, se, se),
		    		HFactory.createColumn(GlobalVar.SERVICE_UPDATE_PERIOD, updatePeriod, se, se),
		    		HFactory.createColumn(GlobalVar.SERVICE_SECTION, section, se, se),
		    		HFactory.createColumn(GlobalVar.LONGITUDE, longitude, se, se),
		    		HFactory.createColumn(GlobalVar.LATITUDE, latitude, se, se)
			);
		
		//We create a super column
		HSuperColumn superCol = HFactory.createSuperColumn(scKey, columns, se, se, se);
		// We insert the columns in a super column inside the database
		Mutator<String> m = HFactory.createMutator(ks, se);		
		MutationResult mr = m.insert(rowKey, cf, superCol	);
		logger.info("Service "+ scKey +" registered into DataBase in: " 
				+ mr.getExecutionTimeMicro() +" microseconds");
		
		String idOSNService = scKey;
		
		//Now we add a Binding between the service and the user
		addBinding(idOSNService, mail);
		
		//Now we register the service in a section
		registerServiceInSection(idOSNService, section);
		
		//Now we register the service in the tags
		//and the tag in the service
		for (String tag : tagList){
			registerServiceInTag(idOSNService, tag);
			registerTagInService(tag, idOSNService);
		}
		
		logger.info("***** Finishing registering service <"+scKey+"> *****");
		return idOSNService;
	}

	@Override
	public void registerServiceInSection(String idOSNService, String section) {
		
		// Set ColumnFamily name
		String cf = "Sections";
		//Set row name
		String rowKey = section;
		
		// Create Column
		HColumn<String, String> col = HFactory.createColumn(idOSNService, idOSNService, se, se);
		// Insert columns
		Mutator<String> m = HFactory.createMutator(ks, se);
	    m.insert(rowKey, cf, col);
	    logger.info("Service <"+idOSNService+"> inserted in section <"+section+">");
	}
	
	@Override
	public void registerServiceInTag(String idOSNService, String tag) {

		// Set ColumnFamily name
		String cf = "Tags";
		//Set row name
		String rowKey = tag;
		
		// Create Column
		HColumn<String, String> col = HFactory.createColumn(idOSNService, idOSNService, se, se);
		// Insert columns
		Mutator<String> m = HFactory.createMutator(ks, se);
	    m.insert(rowKey, cf, col);
	    logger.info("Service <"+idOSNService+"> inserted in tag <"+tag+">");
	    
	}
	
	@Override
	public void deleteService( String idOSNService) {
		// Set ColumnFamily name
		String cf = "Services";
		//Set row name
		String rowKey = getBinding(idOSNService);
		//Set super column name using UUID
		String scKey = idOSNService;
		
		logger.info("***** Starting deleting service <"+scKey+"> *****");
		
		//First we delete the Binding, the Entries, the BindingServiceEntries, the Section and the Tags
		deleteEntriesFromService (idOSNService);
		deleteServiceEntriesBinding(idOSNService);
		deleteTwitter(idOSNService);
		OSNService service = getService(idOSNService);
		deleteServiceFromSection(idOSNService, service.getSection());
		List<String> listTags = getTagsByService(idOSNService);
		for (String tag : listTags){
			deleteServiceFromTag(idOSNService, tag);
			deleteTagFromService(tag, idOSNService);
		}
		deleteBinding(idOSNService, rowKey);
		
		//Now we delete the supercolumn (OSNService)
		Mutator<String> m = HFactory.createMutator(ks, se);	
		MutationResult mr = m.subDelete(rowKey, cf, scKey, null, se, se);


		
		logger.info("Service "+ scKey +" deleted from DataBase in: " 
				+ mr.getExecutionTimeMicro() +" microseconds");
		logger.info("***** Finishing deleting service <"+scKey+"> *****");
	}

	@Override
	public OSNService getService(String idOSNService) {

		OSNService service = null;
		
		// Set ColumnFamily name
		String cf = "Services";
		//Set row name from the binding
		String rowKey = getBinding(idOSNService);
		//Set super column name using UUID
		String scKey = idOSNService;
		
		// get value
		MultigetSubSliceQuery<String, String, String, String> q = 
			HFactory.createMultigetSubSliceQuery(ks, se, se, se, se);
		
	    q.setColumnFamily(cf);
	    q.setSuperColumn(scKey);
	    q.setKeys(rowKey);
	    q.setColumnNames(GlobalVar.SERVICE_ID, GlobalVar.MAIL,
	    		GlobalVar.SERVICE_NAME,GlobalVar.SERVICE_PASSWORD,
	    		GlobalVar.SERVICE_OWNER,GlobalVar.SERVICE_DESCRIPTION,
	    		GlobalVar.SERVICE_UPDATE_PERIOD,GlobalVar.SERVICE_SECTION,
	    		GlobalVar.LONGITUDE,GlobalVar.LATITUDE );
	    
	    QueryResult<Rows<String, String, String>> result = q.execute();
	    
		//We obtain all the rows (in this case just one) and we iterate it to build a OSNService
		Rows<String, String, String> rows = result.get();
			
	    for (Row<String, String, String> r : rows) {

	    	logger.info("Columns size:" +r.getColumnSlice().getColumns().size()  );
	    	if (! r.getColumnSlice().getColumns().isEmpty()){
		        if ( r.getColumnSlice().getColumnByName(GlobalVar.SERVICE_ID).getValue().equals(scKey)  ){
			        service = new OSNService();
			        service.setIdOSNService(r.getColumnSlice().getColumnByName(GlobalVar.SERVICE_ID).getValue());
		        	service.setMail(r.getColumnSlice().getColumnByName(GlobalVar.MAIL).getValue());
			        service.setServiceName(r.getColumnSlice().getColumnByName(GlobalVar.SERVICE_NAME).getValue());
			        service.setServicePassword(r.getColumnSlice().getColumnByName(GlobalVar.SERVICE_PASSWORD).getValue());
			        service.setOwner(r.getColumnSlice().getColumnByName(GlobalVar.SERVICE_OWNER).getValue());
			        service.setDescription(r.getColumnSlice().getColumnByName(GlobalVar.SERVICE_DESCRIPTION).getValue());
			        service.setUpdatePeriod(r.getColumnSlice().getColumnByName(GlobalVar.SERVICE_UPDATE_PERIOD).getValue());
			        service.setSection(r.getColumnSlice().getColumnByName(GlobalVar.SERVICE_SECTION).getValue());
			        service.setLongitude(r.getColumnSlice().getColumnByName(GlobalVar.LONGITUDE).getValue());
			        service.setLatitude(r.getColumnSlice().getColumnByName(GlobalVar.LATITUDE).getValue());
		        }
	    	}
	    }
	    
	    //Now we add the tags to the Service
	    List<String> listTags = getTagsByService(idOSNService);
	    for (String tag : listTags) {
			service.getTagList().add(tag);
		}
	    
	    if (service==null) {
	        logger.info("Service not found... ");  
	    }
	    else {
	    	logger.info("Returning loaded Service... ");
	    }
	    return service;
	}

	@Override
	public List<OSNService> getAllServices() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<OSNService> getServicesBySection(String section) {
		List <OSNService> listServices = new ArrayList<OSNService>();
		
		// Set ColumnFamily name
		String cf = "Sections";
		//Set row name
		String rowKey = section;
		
		// get Services
		MultigetSliceQuery<String, String, String> multigetSliceQuery =
		    HFactory.createMultigetSliceQuery(ks, se, se, se);
		multigetSliceQuery.setColumnFamily(cf);
		multigetSliceQuery.setKeys(rowKey); //In this case we want just one row_key
		multigetSliceQuery.setRange("", "", true, 100); //Count variable is the maximum number of columns. Reverse mode true
		QueryResult<Rows<String, String, String>> result = multigetSliceQuery.execute();

		//We obtain all the rows and we iterate it to build a list of services
		Rows<String, String, String> orderedRows = result.get();

		String idOSNService = null;
		String mail = null;
	    for (Row<String, String, String> r : orderedRows) {
	    	if (! r.getColumnSlice().getColumns().isEmpty()){
	    		for (HColumn<String, String> col: r.getColumnSlice().getColumns()){
	    			idOSNService = col.getName();
	    			mail = getBinding(idOSNService);
	    			//Now we have to call getService() and load the list
	    			listServices.add(getService(idOSNService));
	    		}
	    	}
	    }
		logger.info("Getting services of section: "+section);
		return listServices;
	}

	@Override
	public void deleteServiceFromSection(String idOSNService, String section) {
		// Set ColumnFamily name
		String cf = "Sections";
		//Set row name
		String rowKey = section;
		
	    //remove value
		Mutator<String> m = HFactory.createMutator(ks, se);
	    m.delete(rowKey, cf, idOSNService, se);
		logger.info("Deleting service <"+idOSNService+"> of section :"+section);
	}
	
	@Override
	public List<OSNService> getServicesByTag(String tag) {
		List <OSNService> listServices = new ArrayList<OSNService>();
		
		// Set ColumnFamily name
		String cf = "Tags";
		//Set row name
		String rowKey = tag;
		
		// get Services
		MultigetSliceQuery<String, String, String> multigetSliceQuery =
		    HFactory.createMultigetSliceQuery(ks, se, se, se);
		multigetSliceQuery.setColumnFamily(cf);
		multigetSliceQuery.setKeys(rowKey); //In this case we want just one row_key
		multigetSliceQuery.setRange("", "", true, 100); //Count variable is the maximum number of columns. Reverse mode true
		QueryResult<Rows<String, String, String>> result = multigetSliceQuery.execute();

		//We obtain all the rows and we iterate it to build a list of services
		Rows<String, String, String> orderedRows = result.get();

		String idOSNService = null;
		String mail = null;
	    for (Row<String, String, String> r : orderedRows) {
	    	if (! r.getColumnSlice().getColumns().isEmpty()){
	    		for (HColumn<String, String> col: r.getColumnSlice().getColumns()){
	    			idOSNService = col.getName();
	    			mail = getBinding(idOSNService);
	    			//Now we have to call getService() and load the list
	    			listServices.add(getService( idOSNService));
	    		}
	    	}
	    }
		logger.info("Getting services of tag: "+tag);
		return listServices;
	}

	@Override
	public void deleteServiceFromTag(String idOSNService, String tag) {
		// Set ColumnFamily name
		String cf = "Tags";
		//Set row name
		String rowKey = tag;
		
	    //remove value
		Mutator<String> m = HFactory.createMutator(ks, se);
	    m.delete(rowKey, cf, idOSNService, se);
		logger.info("Deleting service <"+idOSNService+"> of tag :"+tag);
	}
	
	@Override
	public List<OSNService> getServicesByMail(String mail) {
		
		List <OSNService> listServices = new ArrayList<OSNService>();
		
		// Set ColumnFamily name
		String cf = "Services";
		//Set row name
		String rowKey = mail;

		
		MultigetSuperSliceQuery<String, String, String, String> q = 
			HFactory.createMultigetSuperSliceQuery(ks, se, se, se,se);
		q.setColumnFamily(cf);
		q.setKeys(rowKey);
		q.setRange("", "", false, 100); //with range we specify the maximum number of results (in our case 100)

		QueryResult<SuperRows<String, String, String, String>> result = q.execute();
		SuperRows<String, String, String, String> rows = result.get();
		
		SuperRow<String, String, String, String> sr = rows.getByKey(rowKey);
		logger.info("SuperRow key: "+sr.getKey());

		
//		for (SuperRow<String, String, String, String> sr : rows) {
			List <HSuperColumn<String, String, String>>  listSuperColumns = sr.getSuperSlice().getSuperColumns();
			for (HSuperColumn<String, String, String> hSuperColumn : listSuperColumns) {
				//We obtain the scKey
				String scKey = hSuperColumn.getName();
				logger.info("SuperColumn key: "+scKey);
				OSNService service = new OSNService(); 
				List<HColumn<String, String>> listColumns = hSuperColumn.getColumns(); 
				for (HColumn<String, String> hColumn : listColumns) {
					logger.info("The value of the Column is: "+hColumn.getName());
					if (hColumn.getName().equals(GlobalVar.MAIL)){
						service.setMail(hColumn.getValue());
					} 
					else if (hColumn.getName().equals(GlobalVar.SERVICE_ID)) {
						service.setIdOSNService(hColumn.getValue());
					} 
					else if (hColumn.getName().equals(GlobalVar.SERVICE_NAME)) {
						service.setServiceName(hColumn.getValue());
					} 
					else if (hColumn.getName().equals(GlobalVar.SERVICE_DESCRIPTION)) {
						service.setDescription(hColumn.getValue());
					} 
					else if (hColumn.getName().equals(GlobalVar.SERVICE_PASSWORD)) {
						service.setServicePassword(hColumn.getValue());
					} 
					else if (hColumn.getName().equals(GlobalVar.SERVICE_OWNER)) {
						service.setOwner(hColumn.getValue());
					} 
					else if (hColumn.getName().equals(GlobalVar.SERVICE_UPDATE_PERIOD)) {
						service.setUpdatePeriod(hColumn.getValue());
					} 
					else if (hColumn.getName().equals(GlobalVar.SERVICE_SECTION)) {
						service.setSection(hColumn.getValue());
					} 
					else if (hColumn.getName().equals(GlobalVar.LATITUDE)) {
						service.setLatitude(hColumn.getValue());
					} 
					else if (hColumn.getName().equals(GlobalVar.LONGITUDE)) {
						service.setLongitude(hColumn.getValue());
					} 
		        
				}
				listServices.add(service);		 
			}
//		}

	    
	    if (listServices.isEmpty()) {
	        logger.info("The user does not have services... ");  
	    }
	    else {
	    	logger.info("Returning list of services... ");
	    }
		return listServices;
	}

	
	
	@Override
	public String addEntry(String idOSNService, XMLGregorianCalendar timeStamp,
			String value, String longitude, String latitude ) {
		// Set ColumnFamily name
		String cf = "Entries";
		//Set row name
		//String rowKey = UUID.randomUUID().toString(); 
		long clock = HFactory.createClock();
		//UUID uuid = TimeUUIDUtils.getTimeUUID(clock);
		//String rowKey = uuid.toString(); 
		String rowKey = String.valueOf(clock);
		
		if (getBinding(idOSNService)!=null){
			//Now we have to add a binding between the entry and the service
			addServiceEntriesBinding(idOSNService, rowKey);
	
			// Create Column
			HColumn<String, String> colIdOSNService = HFactory.createColumn(GlobalVar.SERVICE_ID, idOSNService, se, se);
			HColumn<String, String> colIdOSNEntry = HFactory.createColumn(GlobalVar.ENTRY_ID, rowKey, se, se);
			HColumn<String, String> colTimeStamp = HFactory.createColumn(GlobalVar.ENTRY_TIME_STAMP, timeStamp.toString(), se, se);
			HColumn<String, String> colValue = HFactory.createColumn(GlobalVar.ENTRY_VALUE, value, se, se);
			HColumn<String, String> colLatitude = HFactory.createColumn(GlobalVar.LATITUDE, latitude, se, se);
			HColumn<String, String> colLongitude = HFactory.createColumn(GlobalVar.LONGITUDE, longitude, se, se);
			
			// Insert columns
			Mutator<String> m = HFactory.createMutator(ks, se);
		    m.insert(rowKey, cf, colIdOSNService);
		    m.insert(rowKey, cf, colIdOSNEntry);
		    m.insert(rowKey, cf, colTimeStamp);
		    m.insert(rowKey, cf, colValue);
		    m.insert(rowKey, cf, colLatitude);
		    m.insert(rowKey, cf, colLongitude);
		    
		    //logger.info("Entry <"+rowKey+"> inserted");
	
		    String idOSNEntry = rowKey;
		    // We also insert in the Last entries 
		    addLastEntry(idOSNService, idOSNEntry);
		    
		    return idOSNEntry;
		}else{
			logger.info("You are trying to add an Entry to a Service that does not exist");
			return null;
		}
	}

	@Override
	public void deleteEntry(String IdOSNEntry) {
		// TODO Auto-generated method stub

	}
	
	@Override
	public void deleteEntriesFromService (String idOSNService){
		
		// Set ColumnFamily name
		String cf = "Entries";
		
		List<String> listIDEntry = getSeviceEntriesBinding(idOSNService);
		for (String entryID : listIDEntry) {
			Mutator<String> m = HFactory.createMutator(ks, se);
		    //remove the Row... be careful with "range ghosts", maybe the row still alive
		    m.addDeletion(entryID, cf);
		    m.execute();
		}
	    logger.info("Deleting Entries from Service <"+idOSNService+">");
	}
	
	@Override
	public List<OSNEntry> getEntriesFromService(String idOSNService, int numEntries)  {

		List <OSNEntry> listEntries = new ArrayList<OSNEntry>();
		OSNEntry entry = null;
		
		// Set ColumnFamily name
		String cf = "Entries";
		//Set row name
		String rowKey = null;
		
		List<String> listIDEntries = getSeviceEntriesBinding(idOSNService, numEntries);
		for (String idEntry : listIDEntries) {
			
			rowKey = idEntry;
			// get Services
			MultigetSliceQuery<String, String, String> multigetSliceQuery =
			    HFactory.createMultigetSliceQuery(ks, se, se, se);
			multigetSliceQuery.setColumnFamily(cf);
			multigetSliceQuery.setKeys(rowKey); //In this case we want just one row_key
			multigetSliceQuery.setRange("", "", false, 10); //Count variable is the maximum number of columns
			QueryResult<Rows<String, String, String>> result = multigetSliceQuery.execute();

			//We obtain all the rows and we iterate it to build a list of services
			Rows<String, String, String> rows = result.get();

		    for (Row<String, String, String> r : rows) {
		    	if (! r.getColumnSlice().getColumns().isEmpty()){

		    		entry = new OSNEntry();
		    		entry.setIdOSNEntry(r.getColumnSlice().getColumnByName(GlobalVar.ENTRY_ID).getValue());
		    		entry.setValue(r.getColumnSlice().getColumnByName(GlobalVar.ENTRY_VALUE).getValue());
					try {
			    		GregorianCalendar gcal = new GregorianCalendar();
			    		String dateString = r.getColumnSlice().getColumnByName(GlobalVar.ENTRY_TIME_STAMP).getValue();
			    		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
						Date date = sdf.parse(dateString);
			    		gcal.setTime(date);
			    		XMLGregorianCalendar xmlgcal = DatatypeFactory.newInstance().newXMLGregorianCalendar(gcal);
			    		entry.setTimeStamp(xmlgcal);
					} catch (Exception e) {
						// TODO Auto-generated catch block
						entry.setTimeStamp(null);
					}
					entry.setLatitude(r.getColumnSlice().getColumnByName(GlobalVar.LATITUDE).getValue());
					entry.setLongitude(r.getColumnSlice().getColumnByName(GlobalVar.LONGITUDE).getValue());
		    		
		    		listEntries.add(entry);

		    	}
		    }
		}
		logger.info("Getting entries from service <"+idOSNService+">");
		
		return listEntries;
		
	}

	
	@Override
	public OSNEntry getEntry(String idOSNEntry) {
		OSNEntry entry = null;
		
		// Set ColumnFamily name
		String cf = "Entries";
		//Set row name
		String rowKey = idOSNEntry;
		
		
		// get User
		MultigetSliceQuery<String, String, String> multigetSliceQuery =
		    HFactory.createMultigetSliceQuery(ks, se, se, se);
		multigetSliceQuery.setColumnFamily(cf);
		multigetSliceQuery.setKeys(rowKey); //In this case we want just one row_key
		multigetSliceQuery.setRange("", "", false, 20); //Count variable is the maximum number of columns
		QueryResult<Rows<String, String, String>> result = multigetSliceQuery.execute();

		//We obtain all the rows (in this case just one) and we iterate it to build a User
		Rows<String, String, String> orderedRows = result.get();
	
	    for (Row<String, String, String> r : orderedRows) {
	        	
	    	if (! r.getColumnSlice().getColumns().isEmpty()){
	    		if (r.getColumnSlice().getColumnByName(GlobalVar.ENTRY_ID).getValue().equals(rowKey)){
			        entry = new OSNEntry();
			        entry.setIdOSNEntry(r.getColumnSlice().getColumnByName(GlobalVar.ENTRY_ID).getValue());
			        entry.setValue(r.getColumnSlice().getColumnByName(GlobalVar.ENTRY_VALUE).getValue());
			        try {
			    		GregorianCalendar gcal = new GregorianCalendar();
			    		String dateString = r.getColumnSlice().getColumnByName(GlobalVar.ENTRY_TIME_STAMP).getValue();
			    		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
						Date date = sdf.parse(dateString);
			    		gcal.setTime(date);
			    		XMLGregorianCalendar xmlgcal = DatatypeFactory.newInstance().newXMLGregorianCalendar(gcal);
			    		entry.setTimeStamp(xmlgcal);
					} catch (Exception e) {
						// TODO Auto-generated catch block
						entry.setTimeStamp(null);
					}
					entry.setLatitude(r.getColumnSlice().getColumnByName(GlobalVar.LATITUDE).getValue());
					entry.setLongitude(r.getColumnSlice().getColumnByName(GlobalVar.LONGITUDE).getValue());
		    	}
	    	}
	    }
		
	    logger.info("Returning loaded Entry... ");

		return entry;
	}
	
	@Override
	public OSNEntry getLastEntry(String idOSNService) {
		
		OSNEntry entry = null;
		
		// Set ColumnFamily name
		String cf = "LastEntries";
		//Set row name
		String rowKey = idOSNService;

		// get User
		MultigetSliceQuery<String, String, String> multigetSliceQuery =
		    HFactory.createMultigetSliceQuery(ks, se, se, se);
		multigetSliceQuery.setColumnFamily(cf);
		multigetSliceQuery.setKeys(rowKey); //In this case we want just one row_key
		multigetSliceQuery.setRange("", "", false, 20); //Count variable is the maximum number of columns
		QueryResult<Rows<String, String, String>> result = multigetSliceQuery.execute();

		//We obtain all the rows (in this case just one) and we iterate it to build a User
		Rows<String, String, String> orderedRows = result.get();

	    for (Row<String, String, String> r : orderedRows) {
	    	if (! r.getColumnSlice().getColumns().isEmpty()){

	    			String idOSNEntry = r.getColumnSlice().getColumnByName(GlobalVar.ENTRY_LAST_ID).getValue();
	    			//Now we obtain the entry
			        entry = getEntry(idOSNEntry);
	    	}
	    }
		
	    logger.info("Returning loaded Last Entry... ");

		return entry;
	}

	@Override
	public List<OSNEntry> getEntriesBetween2Dates(String idOSNService,
			String startDate, String endDate) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void addBinding(String idOSNService, String mail) {
		// Set ColumnFamily name
		String cf = "Bindings";
		//Set row name
		String rowKey = idOSNService;
		
		// Create Column
		HColumn<String, String> col = HFactory.createColumn("mail", mail, se, se);
		// Insert columns
		Mutator<String> m = HFactory.createMutator(ks, se);
	    m.insert(rowKey, cf, col);
	    logger.info("Adding Binding between Service <"+idOSNService+"> and User <"+mail+">");
		
	}

	@Override
	public String getBinding(String idOSNService) {
	    
		// Set ColumnFamily name
		String cf = "Bindings";
		//Set row name
		String rowKey = idOSNService;
		
		// get value
	    ColumnQuery<String, String, String> q = HFactory.createColumnQuery(ks, se, se, se);
	    q.setName(GlobalVar.MAIL).setColumnFamily(cf);
	    QueryResult<HColumn<String, String>> r = q.setKey(rowKey).execute();
	    
	    HColumn<String, String> col = r.get();

	    if (col!=null){
		    String name = col.getName();
		    String value = col.getValue();   
		    logger.info("Getting Binding between Service <"+idOSNService+"> and User <"+value+">"); 
			return value;
	    } else {
	    	logger.info("The Binding between Service <"+idOSNService+"> and a stored User does not exist"); 
	    	return null;
	    }
	}

	@Override
	public void deleteBinding(String idOSNService, String mail) {
		// Set ColumnFamily name
		String cf = "Bindings";
		//Set row name
		String rowKey = idOSNService;
		
	    //remove value
		Mutator<String> m = HFactory.createMutator(ks, se);
	    m.delete(rowKey, cf, GlobalVar.MAIL, se);
	    logger.info("Deleting Binding between Service <"+idOSNService+"> and User <"+mail+">");
	}

	@Override
	public void registerTagInService(String tag, String idOSNService) {
		// Set ColumnFamily name
		String cf = "ServiceTags";
		//Set row name
		String rowKey = idOSNService;
		
		// Create Column
		HColumn<String, String> col = HFactory.createColumn(tag, tag, se, se);
		// Insert columns
		Mutator<String> m = HFactory.createMutator(ks, se);
	    m.insert(rowKey, cf, col);
	    logger.info("Adding Tag <"+tag+"> inserted in Service <"+idOSNService+">");
		
	}

	@Override
	public void deleteTagFromService(String tag, String idOSNService) {
		// Set ColumnFamily name
		String cf = "ServiceTags";
		//Set row name
		String rowKey = idOSNService;

	    //remove value
		Mutator<String> m = HFactory.createMutator(ks, se);
	    m.delete(rowKey, cf, tag, se);
		logger.info("Deleting tag <"+tag+"> of service <"+idOSNService+">");
		
	}

	@Override
	public List<String> getTagsByService(String idOSNService) {
		List <String> listTags = new ArrayList<String>();
		
		// Set ColumnFamily name
		String cf = "ServiceTags";
		//Set row name
		String rowKey = idOSNService;
		
		// get Services
		MultigetSliceQuery<String, String, String> multigetSliceQuery =
		    HFactory.createMultigetSliceQuery(ks, se, se, se);
		multigetSliceQuery.setColumnFamily(cf);
		multigetSliceQuery.setKeys(rowKey); //In this case we want just one row_key
		multigetSliceQuery.setRange("", "", false, 20); //Count variable is the maximum number of columns
		QueryResult<Rows<String, String, String>> result = multigetSliceQuery.execute();

		//We obtain all the rows and we iterate it to build a list of services
		Rows<String, String, String> orderedRows = result.get();

		String tag = null;
	    for (Row<String, String, String> r : orderedRows) {
	    	if (! r.getColumnSlice().getColumns().isEmpty()){
	    		for (HColumn<String, String> col: r.getColumnSlice().getColumns()){
	    			tag = col.getName();
	    			listTags.add(tag);
	    		}
	    	}
	    }
		logger.info("Getting tags from service <"+idOSNService+">");
		return listTags;
	}

	@Override
	public void addServiceEntriesBinding(String idOSNService, String idOSNEntry) {
		// Set ColumnFamily name
		String cf = "ServiceEntriesBindings";
		//Set row name
		String rowKey = idOSNService;
		
		// Create Column
		HColumn<String, String> col = HFactory.createColumn(idOSNEntry, idOSNEntry, se, se);
		// Insert columns
		Mutator<String> m = HFactory.createMutator(ks, se);
	    m.insert(rowKey, cf, col);
	    //logger.info("Binding Entry <"+idOSNEntry+"> with Service <"+idOSNService+">");
		
	}

	@Override
	public List<String> getSeviceEntriesBinding(String idOSNService,
			int numOfEntries) {
		List<String> listEntries = new ArrayList<String>();
		
		// Set ColumnFamily name
		String cf = "ServiceEntriesBindings";
		//Set row name
		String rowKey = idOSNService;
		
		// get Services
		MultigetSliceQuery<String, String, String> multigetSliceQuery =
		    HFactory.createMultigetSliceQuery(ks, se, se, se);
		multigetSliceQuery.setColumnFamily(cf);
		multigetSliceQuery.setKeys(rowKey); //In this case we want just one row_key
		multigetSliceQuery.setRange("", "", true, numOfEntries); //Count variable is the maximum number of columns (entries). True for reverse mode
		QueryResult<Rows<String, String, String>> result = multigetSliceQuery.execute();

		//We obtain all the rows and we iterate it to build a list of services
		Rows<String, String, String> orderedRows = result.get();

		String entry = null;
	    for (Row<String, String, String> r : orderedRows) {
	    	if (! r.getColumnSlice().getColumns().isEmpty()){
	    		for (HColumn<String, String> col: r.getColumnSlice().getColumns()){
	    			entry = col.getName();
	    			listEntries.add(entry);
	    		}
	    	}
	    }
		logger.info("Getting entries from service <"+idOSNService+">");
		return listEntries;
	}
	
	@Override
	public List<String> getSeviceEntriesBinding(String idOSNService) {
		
		List<String> listEntries = new ArrayList<String>();
		
		// Set ColumnFamily name
		String cf = "ServiceEntriesBindings";
		//Set row name
		String rowKey = idOSNService;
		
		// get Services
		MultigetSliceQuery<String, String, String> multigetSliceQuery =
		    HFactory.createMultigetSliceQuery(ks, se, se, se);
		multigetSliceQuery.setColumnFamily(cf);
		multigetSliceQuery.setKeys(rowKey); //In this case we want just one row_key
		multigetSliceQuery.setRange("", "", true, 1000000); //Count variable is the maximum number of columns (entries). True for reverse mode
		QueryResult<Rows<String, String, String>> result = multigetSliceQuery.execute();

		//We obtain all the rows and we iterate it to build a list of services
		Rows<String, String, String> orderedRows = result.get();

		String entry = null;
	    for (Row<String, String, String> r : orderedRows) {
	    	if (! r.getColumnSlice().getColumns().isEmpty()){
	    		for (HColumn<String, String> col: r.getColumnSlice().getColumns()){
	    			entry = col.getName();
	    			listEntries.add(entry);
	    		}
	    	}
	    }
		logger.info("Getting entries from service <"+idOSNService+">");
		return listEntries;
	}
	
// 	Duplicated for trying to sort the columns	
//	@Override
//	public List<String> getSeviceEntriesBinding(String idOSNService) {
//		
//		List<String> listEntries = new ArrayList<String>();
//		
//		// Set ColumnFamily name
//		String cf = "ServiceEntriesBindings";
//		//Set row name
//		String rowKey = idOSNService;
//		
//		// get Services
//		RangeSlicesQuery<String, String, String> rangeSliceQuery =
//		    HFactory.createRangeSlicesQuery(ks, se, se, se);
//		rangeSliceQuery.setColumnFamily(cf);
//		rangeSliceQuery.setKeys(rowKey,""); //In this case we want just one row_key
//		rangeSliceQuery.setRange("", "", true, 1000); //Count variable is the maximum number of columns. True for reverse mode
//		QueryResult<OrderedRows<String, String, String>> result = rangeSliceQuery.execute();
//
//		//We obtain all the rows and we iterate it to build a list of services
//		OrderedRows<String, String, String> orderedRows = result.get();
//
//		String entry = null;
//	    for (Row<String, String, String> r : orderedRows) {
//	    	if (! r.getColumnSlice().getColumns().isEmpty()){
//	    		for (HColumn<String, String> col: r.getColumnSlice().getColumns()){
//	    			entry = col.getName();
//	    			listEntries.add(entry);
//	    		}
//	    	}
//	    }
//		logger.info("Getting entries from service <"+idOSNService+">");
//		return listEntries;
//	}

	@Override
	public void deleteServiceEntriesBinding(String idOSNService) {
		// Set ColumnFamily name
		String cf = "ServiceEntriesBindings";
		//Set row name
		String rowKey = idOSNService;
		
		Mutator<String> m = HFactory.createMutator(ks, se);
	    //remove the Row... be careful with "range ghosts", maybe the row still alive
	    m.addDeletion(rowKey, cf);
	    m.execute();
	    logger.info("Deleting Binding between Service <"+idOSNService+"> and all Entries");
		
	}

	@Override
	public void addLastEntry(String idOSNService, String idOSNEntry) {

		// Set ColumnFamily name
		String cf = "LastEntries";
		//Set row name
		String rowKey = idOSNService;
		
		// Create Column
		HColumn<String, String> col = HFactory.createColumn(GlobalVar.ENTRY_LAST_ID, idOSNEntry, se, se);
		// Insert columns
		Mutator<String> m = HFactory.createMutator(ks, se);
	    m.insert(rowKey, cf, col);
	    //logger.info("Adding Last Entry <"+idOSNEntry+"> of Service <"+idOSNService+">");
	}

	@Override
	public void addTwitter (String idOSNService, 
			String consumerKey, String consumerSecret,
			String token, String tokenSecret) {
		
		// Set ColumnFamily name
		String cf = "Twitter";
		//Set row name
		String rowKey = idOSNService;
		
		// Create Column
		HColumn<String, String> colTwitterConsumerKey = HFactory.createColumn(GlobalVar.TWITTER_CONSUMER_KEY, consumerKey, se, se);
		HColumn<String, String> colTwitterConsumerSecret = HFactory.createColumn(GlobalVar.TWITTER_CONSUMER_SECRET, consumerSecret, se, se);
		HColumn<String, String> colTwitterToken = HFactory.createColumn(GlobalVar.TWITTER_TOKEN, token, se, se);
		HColumn<String, String> colTwitterTokenSecret = HFactory.createColumn(GlobalVar.TWITTER_TOKEN_SECRET, tokenSecret, se, se);
		// Insert columns
		Mutator<String> m = HFactory.createMutator(ks, se);
	    m.insert(rowKey, cf, colTwitterConsumerKey );
	    m.insert(rowKey, cf, colTwitterConsumerSecret);
	    m.insert(rowKey, cf, colTwitterToken);
	    m.insert(rowKey, cf, colTwitterTokenSecret);
	    
	    logger.info("Twitter user added ");  
		
	}

	@Override
	public OSNService getTwitter(String idOSNService) {
		
		OSNService service = null;
		
		// Set ColumnFamily name
		String cf = "Twitter";
		//Set row name
		String rowKey = idOSNService;
		
		
		// get User
		MultigetSliceQuery<String, String, String> multigetSliceQuery =
		    HFactory.createMultigetSliceQuery(ks, se, se, se);
		multigetSliceQuery.setColumnFamily(cf);
		multigetSliceQuery.setKeys(rowKey); //In this case we want just one row_key
		multigetSliceQuery.setRange("", "", false, 20); //Count variable is the maximum number of columns
		QueryResult<Rows<String, String, String>> result = multigetSliceQuery.execute();
		

		//We obtain all the rows (in this case just one) and we iterate it to build a User
		Rows<String, String, String> orderedRows = result.get();
	
		
	    for (Row<String, String, String> r : orderedRows) {
	        	
	    	if (! r.getColumnSlice().getColumns().isEmpty()){
			        service = new OSNService();
			        service.setTwitterConsumerKey(r.getColumnSlice().getColumnByName(GlobalVar.TWITTER_CONSUMER_KEY).getValue());
			        service.setTwitterConsumerSecret(r.getColumnSlice().getColumnByName(GlobalVar.TWITTER_CONSUMER_SECRET).getValue());
			        service.setTwitterToken(r.getColumnSlice().getColumnByName(GlobalVar.TWITTER_TOKEN).getValue());
			        service.setTwitterTokenSecret(r.getColumnSlice().getColumnByName(GlobalVar.TWITTER_TOKEN_SECRET).getValue());
	    	}
	    }
		
	    if (service==null) {
	        logger.info("Twitter user not found... ");  
	    }
	    else {
	    	logger.info("Returning loaded Twitter... ");
	    }
		return service;
	}


	@Override
	public void deleteTwitter(String idOSNService) {
		// Set ColumnFamily name
		String cf = "Twitter";
		//Set row name
		String rowKey = idOSNService;
		
		Mutator<String> m = HFactory.createMutator(ks, se);
	    //remove the Row... be careful with "range ghosts", maybe the row still alive
	    m.addDeletion(rowKey, cf);
	    m.execute();
	    logger.info("Deleting Twitter account <"+idOSNService+">");
		
	}

	@Override
	public boolean loginService(String idOSNService, String servicePassword) {
		
		// Set ColumnFamily name
		String cf = "Services";
		//Set row name from the binding
		String rowKey = getBinding(idOSNService);
		if (rowKey==null){
	    	logger.info("FAIL: Service is not in the System");
			return false;
		}
		//Set super column name using UUID
		String scKey = idOSNService;
		
		// get value
		MultigetSubSliceQuery<String, String, String, String> q = 
			HFactory.createMultigetSubSliceQuery(ks, se, se, se, se);
		
	    q.setColumnFamily(cf);
	    q.setSuperColumn(scKey);
	    q.setKeys(rowKey);
	    q.setColumnNames(GlobalVar.SERVICE_ID, GlobalVar.SERVICE_PASSWORD);
	    
	    QueryResult<Rows<String, String, String>> result = q.execute();
	    
		//We obtain all the rows (in this case just one) and we iterate it to build a OSNService
		Rows<String, String, String> rows = result.get();
			
	    for (Row<String, String, String> r : rows) {

	    	logger.info("Columns size:" +r.getColumnSlice().getColumns().size()  );
	    	if (! r.getColumnSlice().getColumns().isEmpty()){
		        if ( r.getColumnSlice().getColumnByName(GlobalVar.SERVICE_ID).getValue().equals(scKey)  ){
		        	String storedPassword = r.getColumnSlice().getColumnByName(GlobalVar.SERVICE_PASSWORD).getValue();
		        	if (storedPassword.equals(servicePassword)){
		        		logger.info("OK: Service password is correct");
		        		return true;
		        	}else {
		        		logger.info("FAIL: Service password is incorrect");
		        		return false;
		        	}
		        }
	    	}
	    }
	    logger.info("There are some problems with the Service storage");
		return false;
	}


}
